# -*- coding:utf-8 -*-
import io
from app.features.enum.edata_type import EDataType as DataType
from app.features.service.sheet_info import FieldInfo, SheetInfo

from app.common.global_values import *
from app.features.service.util import *
from app.features.enum.etable_string_key_type import ETableStringKeyType as TableStringKeyType
from app.features.enum.etable_string_value_type import ETableStringValueType as TableStringValueType
from app.features.service.field_info import (
    DataInIndexDefine,
    TableElementDefine
)
from app.features.service.sheet_analysis_util import SheetAnalysisUtil


class TableExportToJsonUtil:
    """
    导出json文件实现类
    """
    # 缩进json的字符串
    _JSON_INDENTATION_STRING = "\t"

    def __init__(self, controller):
        self.controller = controller
        
    def _progressDisplay(self, msg, level):
        self.controller.progressDisplay(msg, level)

    def export_to_json(self, tableInfo: SheetInfo):
        self._progressDisplay("export_to_json 导出成json文件", "INFO")
        return None
        """
		导出成json文件
		"""
        stringBuilder = io.StringIO
        stringBuilder.write("[")
        # 获取所有解析后的数据
        allField = tableInfo.get_all_fieldInfo()
        dataCount = len(tableInfo.get_keyColumn_fieldInfo().data)
        fieldCount = len(allField)
        # 逐行读取表格内容生成json
        for row in range(0, dataCount):
            # 生成一行数据json object的开头
            stringBuilder.write("{")
            for column in range(0, fieldCount):
                oneFieldString = self._get_one_field(allField[column], row)
                if oneFieldString == None:
                    self._progressDisplay(
                        f"额外导出表格{tableInfo.tableName}为json文件失败", "ERROR")
                    return False
                else:
                    stringBuilder.write(oneFieldString)
            # 去掉本行最后一个字符后多余逗号
            stringBuilder.write(stringBuilder.getvalue().rstrip(','))
            # 生成一行数据json object的结尾
            stringBuilder.write("}")
            # 每行的json object后加英文逗号
            stringBuilder.write(",")

        # 去掉最后一行后多余的逗号
        if len(stringBuilder.getvalue()) > 1:
            stringBuilder.write(stringBuilder.getvalue().rstrip(','))
        # 生成json字符串结尾
        stringBuilder.write("]")
        # 格式化
        exportString = self._FormatJson(stringBuilder.getvalue())
        # 保存为json文件
        # if util.SaveJsonFile(tableInfo.tableName, exportString):
        # 	self._progressDisplay("保存为json文件成功")
        # 	return True
        # else:
        # 	self._progressDisplay("保存为json文件失败")
        # 	return False

    def _get_one_field(self, fieldInfo: FieldInfo, row):
        stringBuilder = io.StringIO
        # 变量名,注意array下属的子元素在json中不含key的声明
        if not fieldInfo.parentField != None and fieldInfo.parentField.dataType == DataType.Array:
            stringBuilder.write("\"")
            stringBuilder.write(fieldInfo.fieldName)
            stringBuilder.write("\"")
            stringBuilder.write(":")
        # 对应数据值
        value = None
        if fieldInfo.dataType == DataType.Int or fieldInfo.dataType == DataType.Long or fieldInfo.dataType == DataType.Float:
            value = self._get_number_value(fieldInfo, row)
        elif fieldInfo.dataType == DataType.String:
            value = self._get_string_value(fieldInfo, row)
        elif fieldInfo.dataType == DataType.Bool:
            value = self._get_bool_value(fieldInfo, row)
        elif fieldInfo.dataType == DataType.TableString:
            value = self._get_table_string_value(fieldInfo, row)
        elif fieldInfo.dataType == DataType.Dict:
            value = self._get_dict_value(fieldInfo, row)
        elif fieldInfo.dataType == DataType.Array:
            value = self._get_array_value(fieldInfo, row)
        else:
            self._progressDisplay(
                f"_get_one_field函数中未定义{fieldInfo.dataType}类型数据导出至json文件的形式")
            return None
        stringBuilder.write(value)
        # 一个字段结尾加逗号
        stringBuilder.write(",")

        return stringBuilder.getvalue()

    def _get_number_value(self, fieldInfo: FieldInfo, row):
        if fieldInfo.data[row] == None:
            return "0"
        else:
            return str(fieldInfo.data[row])

    def _get_string_value(self, fieldInfo: FieldInfo, row):
        stringBuilder = io.StringIO
        stringBuilder.write("\"")
        stringBuilder.write(str(fieldInfo.data[row]).replace(
            "\n", "\\n").replace("\"", "\\\""))
        stringBuilder.write("\"")

        return stringBuilder.getvalue()

    def _get_bool_value(self,  fieldInfo: FieldInfo, row):
        if bool(fieldInfo.data[row]) == True:
            return "true"
        else:
            return "false"

    def _get_table_string_value(self, fieldInfo: FieldInfo, row):
        if fieldInfo.data[row] != None:
            num = 0
            for index in range(0, len(fieldInfo.dataTypeString)):
                if fieldInfo.dataTypeString[index] == '=':
                    num += 1
            return "[]"

        stringBuilder = io.StringIO
        inputData = str(fieldInfo.data[row])
        # tableString字符串中不允许出现英文引号、斜杠
        if inputData.find("\"") or inputData.find("\\") or inputData.find("/"):
            self._progressDisplay(f"tableString字符串中不允许出现英文引号、斜杠")
            return None

        # 若tableString的key为#seq, 则生成json array,否则生成json object
        brackets = "{"
        if fieldInfo.tableStringFormatDefine.keyDefine.keyType == TableStringKeyType.Seq:
            brackets = "["
        endBrackets = "}"
        if fieldInfo.tableStringFormatDefine.keyDefine.keyType == TableStringKeyType.Seq:
            endBrackets = "]"

        # 每组数据间用英文分号分隔
        allDataString = inputData.split(';')
        # 记录每组数据中的key值(转为字符串后的),不允许出现相同的key(key:每组数据中的key值, value:第几组数据,从0开始记)
        stringKeys = {}
        for i in range(0, len(allDataString)):
            # 根据key的格式定义生成key
            if fieldInfo.tableStringFormatDefine.keyDefine.keyType == TableStringKeyType.Seq:
                continue
            elif fieldInfo.tableStringFormatDefine.keyDefine.keyType == TableStringKeyType.DataInIndex:
                value = self._GetDataInIndexType(
                    fieldInfo.tableStringFormatDefine.keyDefine.dataInIndexDefine, allDataString[i])
                if value == None:
                    if fieldInfo.tableStringFormatDefine.keyDefine.dataInIndexDefine.dataType == DataType.Int \
                            or fieldInfo.tableStringFormatDefine.keyDefine.dataInIndexDefine.dataType == DataType.Long:
                        # 检查key是否在该组数据中重复
                        if value in stringKeys:
                            self._progressDisplay(
                                f"第{stringKeys[value] + 1}组数据与第{i + 1}组数据均为相同的key({value})", "ERROR")
                            return None
                        else:
                            stringKeys[value] = i
                            stringBuilder.write(f"\"{value}\"")
                    elif fieldInfo.tableStringFormatDefine.keyDefine.dataInIndexDefine.dataType == DataType.String:
                        # string型的key不允许为空或纯空格且必须符合变量名的规范
                        value = str(value).strip()
                        if SheetAnalysisUtil.check_field_name(value):
                            # 检查key是否在该组数据中重复
                            if value in stringKeys:
                                self._progressDisplay(
                                    f"第{stringKeys[value] + 1}组数据与第{i + 1}组数据均为相同的key({value})", "ERROR")
                                return None
                            else:
                                stringKeys[value] = i
                                stringBuilder.write(f"\"{value}\"")
                        else:
                            self._progressDisplay(f"tableString中第{i + 1}组数据({allDataString[i]})的key数据存在错误, \
								string型的key不符合变量名定义规范", "ERROR")
                            return None
                    else:
                        self._progressDisplay(
                            f"错误:用_get_table_string_value函数导出非int、long或string型的key值", "ERROR")
                        return None
                stringBuilder.write(":")
            else:
                self._progressDisplay(
                    f"错误:用_get_table_string_value函数导出未知类型的key")
                return None

            # 根据value的格式定义生成value
            if fieldInfo.tableStringFormatDefine.valueDefine.ValueType == TableStringValueType.AllTrue:
                stringBuilder.write("true")
            elif fieldInfo.tableStringFormatDefine.valueDefine.ValueType == TableStringValueType.DataInIndex:
                value = self._GetDataInIndexType(
                    fieldInfo.tableStringFormatDefine.valueDefine.DataInIndexDefine, allDataString[i])
                if value != None:
                    dataType: DataType = fieldInfo.tableStringFormatDefine.valueDefine.DataInIndexDefine.dataType
                    if dataType == DataType.String or dataType == DataType.Lang:
                        stringBuilder.write(f"\"{value}\"")
                    else:
                        stringBuilder.write(value)
            elif fieldInfo.tableStringFormatDefine.valueDefine.ValueType == TableStringValueType.Table:
                num = 0
                for index in range(0, len(fieldInfo.dataTypeString)):
                    if fieldInfo.dataTypeString[index] == '=':
                        num += 1
                if num == 2:
                    brackets = "{"
                    endBrackets = "}"
                    for index in range(0, len(fieldInfo.tableStringFormatDefine.valueDefine.TableValueDefineList), 2):
                        keyDataInIndexDefine: DataInIndexDefine = fieldInfo.tableStringFormatDefine.valueDefine.TableValueDefineList[
                            index].dataInIndexDefine
                        valueDataInIndexDefine: DataInIndexDefine = fieldInfo.tableStringFormatDefine.valueDefine.TableValueDefineList[
                            index+1].dataInIndexDefine

                        key = self._GetDataInIndexType(
                            keyDataInIndexDefine, allDataString[i])
                        if key != None:
                            stringBuilder.write(f"\"{key}\"")
                        stringBuilder.write(":")

                        value = self._GetDataInIndexType(
                            valueDataInIndexDefine, allDataString[i])
                        if value != None:
                            if valueDataInIndexDefine.dataType == DataType.String:
                                stringBuilder.write(f"\"{value}\"")
                            else:
                                stringBuilder.write(value)
                        stringBuilder.write(",")
                    # 去掉最后一个子元素后多余的英文逗号
                    stringBuilder.write(stringBuilder.getvalue().rstrip(","))
                else:
                    stringBuilder.write("[")
                    # 依次输出table中定义的子元素
                    for elementDefine in fieldInfo.tableStringFormatDefine.valueDefine.TableValueDefineList:
                        elementDefine = TableElementDefine(elementDefine)
                        value = self._GetDataInIndexType(
                            elementDefine.dataInIndexDefine, allDataString[i])
                        if value != None:
                            if elementDefine.dataInIndexDefine.dataType == DataType.String:
                                stringBuilder.write(f"\"{value}\"")
                            else:
                                stringBuilder.write(value)
                        stringBuilder.write(",")
                    # 去掉最后一个子元素后多余的英文逗号
                    stringBuilder.write(stringBuilder.getvalue().rstrip(","))
                    stringBuilder.write("]")
            else:
                self._progressDisplay(
                    "错误:用_get_table_string_value函数导出未知类型的value")
                return None
            # 每组数据生成完毕后加逗号
            stringBuilder.write(",")
        # 去掉最后一组后多余的英文逗号
        stringBuilder.write(stringBuilder.getvalue().rstrip(","))
        return f"{brackets}{stringBuilder.getvalue()}{endBrackets}"

    def _GetDataInIndexType(self, define: DataInIndexDefine, oneDataString: str):
        """
        将#1(int)的数据定义解析为要输出的字符串
        """
        # 一组数据中的子元素用英文逗号分隔
        allElementString = oneDataString.strip().split(',')
        # 检查是否存在指定序号的数据
        if len(allElementString) < define.dataIndex:
            self._progressDisplay(
                f"解析#{define.dataIndex}({define.dataType})类型的数据错误,输入的数据中只有{len(allElementString)}个子元素")
            return None
        # 检查是否为指定类型的合法数据
        inputString = allElementString[define.dataIndex - 1]
        if define.dataType != DataType.String:
            inputString = inputString.strip()
        value = self._GetDataStringInTableString(inputString, define.dataType)
        if value == None:
            self._progressDisplay(
                f"解析#{define.dataIndex}({str(define.dataType)})类型的数据错误,")
            return None
        else:
            return value

    def _GetDataStringInTableString(self, inputData: str, dataType: DataType):
        """
        将tableString类型数据字符串中的某个所填数据转为需要输出的字符串
        """
        result = ""
        if dataType == DataType.Bool:
            if "1" == inputData or "true" == inputData:
                result = "true"
            elif "0" == inputData or "false" == inputData:
                result = "false"
            else:
                self._progressDisplay(
                    f"输入的\"{inputData}\"不是合法的bool值,正确填写bool值方式为填1或true代表真,0或false代表假")
                return None
        elif dataType == DataType.Int or dataType == DataType.Long:
            if inputData.isdigit():
                result = int(inputData)
            else:
                self._progressDisplay(f"输入的\"{inputData}\"不是合法的{dataType}类型的值")
                return None
        elif dataType == DataType.Float:
            try:
                result = float(inputData)
            except ValueError:
                self._progressDisplay(f"输入的\"{inputData}\"不是合法的float类型的值")
                result = None
            return result
        elif dataType == DataType.String:
            result = inputData
        else:
            self._progressDisplay(
                f"错误:用_GetDataInTableString函数解析了tableString中不支持的数据类型{dataType}")
            return None

        return result

    def _get_dict_value(self, fieldInfo: FieldInfo, row):
        stringBuilder = io.StringIO
        # 如果该dict数据用-1标为无效,则赋值为null
        if fieldInfo.data[row] == False:
            stringBuilder.write("null")
        else:
            # dict生成json object
            stringBuilder.write("{")
            # 逐个对子元素进行生成
            for childField in fieldInfo.childField:
                oneFieldString = self._get_one_field(childField, row)
                if oneFieldString == None:
                    return None
                else:
                    stringBuilder.write(oneFieldString)

            # 去掉最后一个子元素末尾多余的英文逗号
            stringBuilder.write(stringBuilder.getvalue().rstrip(','))
            stringBuilder.write("}")
        return stringBuilder.getvalue()

    def _get_array_value(self, fieldInfo: FieldInfo, row):
        stringBuilder = io.StringIO
        # 如果该array数据用-1标为无效,则赋值为null
        if fieldInfo.data[row] == False:
            stringBuilder.write("null")
        else:
            # array生成json array
            stringBuilder.write("[")
            # 逐个对子元素进行生成
            hasValidChild = False
            for childField in fieldInfo.childField:
                oneFieldString = self._get_one_field(childField, row)
                if oneFieldString == None:
                    return None
                # json array中不允许null元素
                if "null," != oneFieldString:
                    stringBuilder.write(oneFieldString)
                    hasValidChild = True
            # 去掉最后一个子元素末尾多余的英文逗号
            if hasValidChild:
                stringBuilder.write(stringBuilder.getvalue().rstrip(","))
            stringBuilder.write("]")
        return stringBuilder.getvalue()

    def _FormatJson(self, json):
        """
        将紧凑型的json字符串整理为带缩进和换行的形式,需注意string型值中允许含有括号和\
        """
        stringBuilder = io.StringIO
        level = 0
        isInQuotationMarks = False
        for i in range(0, len(json)):
            c = json[i]
            if c == '[' or c == '{':
                stringBuilder.write(c)
                if isInQuotationMarks == False:
                    stringBuilder.write("\r\n")
                    level += 1
                    stringBuilder.write(self._GetJsonIndentation(level))
            elif c == ']' or c == '}':
                if (isInQuotationMarks == False):
                    stringBuilder.write("\r\n")
                    level -= 1
                    stringBuilder.write(self._GetJsonIndentation(level))
                stringBuilder.write(c)
            elif c == ',':
                stringBuilder.write(c)
                if (isInQuotationMarks == False):
                    stringBuilder.write("\r\n")
                    stringBuilder.write(self._GetJsonIndentation(level))
            elif c == '"':
                stringBuilder.write('"')
                if i > 0 and json[i - 1] != '\\':
                    isInQuotationMarks = not isInQuotationMarks
            else:
                stringBuilder.write(c)

        return stringBuilder.getvalue()

    def _GetJsonIndentation(self, level):
        stringBuilder = io.StringIO
        for i in range(0, level):
            stringBuilder.write(self._JSON_INDENTATION_STRING)
        return stringBuilder.getvalue()
